//
//  MineService.swift
//  SCA
//
//  Created by tjun on 2025/9/1.
//

import Foundation

struct ChallengeModel {
    let models: [ChallengeListModel]
    let total: Int
    let code: String
    let usedCodeNumber: String
    let totalCodeNumber: String
}

struct MineBenefitsInfo {
    let models: [MineBenefitsModel]
    let totalPage: Int
    let ref: Int
    let mySelf: Int
}

struct ConversionInfo {
    let sizeModels: [RingSizeModel]
    let countryCodeModels: [CountryModel]
    let mobileCountryCodeModels: [MobileCountryCodeModel]
}

struct CountryModel {
    let code: String
    let value: String
}

struct MobileCountryCodeModel {
    let code: String
    let value: String
}

struct RingSizeModel {
    let key: String
    let value: String
    let typeModels: [RingTypeModel]
}

struct RingTypeModel {
    let key: String
    let value: String
    let colorModels: [RingColorModel]
}

struct RingColorModel {
    let key: String
    let value: String
}

class MineService {
    
    static func login(username: String, password: String? = nil, success:(() -> Void)? = nil,
                      failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["username"] = username
        parameters["password"] = password
        parameters["step"] = "confirm"
        
        NetworkManager.shared.post(url: APIEndpoint.login, parameters: parameters, success: { data in
            if let result = data as? [String: Any],
               let accessToken = result["token"] as? String,
               let uid = result["uid"] as? Int {
                
                UserInfo.isLogin = true
                UserInfo.username = username
                UserInfo.token = accessToken
                UserInfo.userId = uid
                NotificationCenter.default.post(name: NotificationName.userLoginSuccess, object: nil)
                success?()
            } else {
                failure?(SCAError.dataException)
            }
        }, failure: failure)
    }
    
    static func register(referralCode: String? = nil,  username: String, password: String,  success:(() -> Void)? = nil,
                         failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        if let referral = referralCode {
            parameters["ref"] = referral
        }
        parameters["username"] = username
        parameters["password"] = password
        parameters["password_confirm"] = password
        
        parameters["step"] = "confirm"
        parameters["fid"] = "\(Snowflake.shared.nextId())"
        
        NetworkManager.shared.post(url: APIEndpoint.register, parameters: parameters, success: { data in
            if let result = data as? [String: Any],
               let uid = result["uid"] as? Int {
                
                UserInfo.username = username
                UserInfo.userId = uid
                success?()
            } else {
                failure?(SCAError.dataException)
            }
        }, failure: failure)
    }
    
    
    static func forgetPassword(username: String, password: String, otf: String, success:(() -> Void)? = nil,
                               failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        parameters["username"] = username
        parameters["password"] = password
        parameters["password_confirm"] = password
        parameters["otp_public"] = otf
        parameters["step"] = "confirm"
        
        NetworkManager.shared.post(url: APIEndpoint.forgetPassword, parameters: parameters, success: { data in
            guard let result = data as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
    }
    
    
    static func setLevel2Password(password: String, otf: String, success:(() -> Void)? = nil,
                                  failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        parameters["pin"] = password
        parameters["pin_confirm"] = password
        parameters["otp"] = otf
        parameters["step"] = "confirm"
        
        NetworkManager.shared.post(url: APIEndpoint.setPin, parameters: parameters, success: { data in
            guard let result = data as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
    }
    
    static func bindAccount(username: String, otf: String, success:(() -> Void)? = nil,
                            failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        parameters["username"] = username
        parameters["bind_otp"] = otf
        parameters["step"] = "confirm"
        
        NetworkManager.shared.post(url: APIEndpoint.bindAccount, parameters: parameters, success: { data in
            guard let result = data as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
    }
    
    
    static func load2FAValidatorData(success:((String?, String?) -> Void)? = nil,
                                     failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["step"] = "ini"
        parameters["fid"] = "\(Snowflake.shared.nextId())"
        
        NetworkManager.shared.post(url: APIEndpoint.verify2FA, parameters: parameters, success: { data in
            if let result = data as? [String: Any],
               let auth2fa = result["auth2fa"] as? String,
               let code = result["code"] as? String {
                success?(auth2fa, code)
            } else {
                success?(nil, nil)
            }
        }, failure: failure)
    }
    
    
    static func bind2FAValidator(otp: String, success:(() -> Void)? = nil,
                                 failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["fid"] = "\(Snowflake.shared.nextId())"
        parameters["otp"] = otp
        
        NetworkManager.shared.post(url: APIEndpoint.verify2FA, parameters: parameters, success: { data in
            guard let result = data as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
    }
    
    
    static func loadUserData(success:((UserInfoModel) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["fid"] = "\(Snowflake.shared.nextId())"
        
        NetworkManager.shared.post(url: APIEndpoint.userInfo, parameters: nil, success: { data in
            guard let result = data as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            
            let userInfoModel = UserInfoModel.make(with: result)
            userInfoModel.asyncInsertOrReplace()
            UserInfo.username = userInfoModel.username
            UserInfo.userId = userInfoModel.userId
            success?(userInfoModel)
            
            NotificationCenter.default.post(name: NotificationName.pin2faStateChange, object: nil)
            
            printProperties(userInfoModel)
            
        }, failure: failure)
    }
    
    
    static func changePassword(oldPassword: String, password: String, otf: String, success:(() -> Void)? = nil,
                               failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        parameters["password_current"] = oldPassword
        parameters["password"] = password
        parameters["password_confirm"] = password
        parameters["otp"] = otf
        parameters["step"] = "confirm"
        parameters["fid"] = "\(Snowflake.shared.nextId())"
        
        NetworkManager.shared.post(url: APIEndpoint.changePassword, parameters: parameters, success: { data in
            guard let result = data as? [String: Any],
                  let reset_password = result["reset_password"] as? Bool,
                  reset_password else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
    }
    
    
    static func loadChallengeData(success:((ChallengeModel) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        
        parameters["step"] = "ini"
        parameters["page"] = "1"
        
        NetworkManager.shared.post(url: APIEndpoint.commitmentList, parameters: parameters, success: { data in
            guard let result = data as? [String: Any],
                  let datalist = result["datalist"] as? [String: Any],
                  let data = datalist["data"] as? [String: Any],
                  let info = datalist["info"] as? [String: Any],
                  let code = info["code"] as? String,
                  let totalCodeNumber = info["total"] as? String,
                  let usedCodeNumber = info["used"] as? String,
                  let total_record = datalist["total_record"] as? Int else {
                failure?(SCAError.dataException)
                return
            }
            
            let datas = Array(data.values)
            
            let models: [ChallengeListModel] = datas.compactMap { value in
                guard let dict = value as? [String: Any],
                      let Id = dict["id"] as? Int,
                      let wallet = dict["wallet"] as? String,
                      let amount = dict["amount"] as? String,
                      let status = dict["status"] as? Int,
                      let code = dict["code"] as? String,
                      let account = dict["binded_disp"] as? String,
                      let ldate = dict["ldate"] as? String else {
                    return nil
                }
                
                return ChallengeListModel(Id: Id, date: formatDate(ldate), amount: amount, account: account,  code: code, wallet: wallet, status: status)
            }
            
            let sortModels = models.sorted { $0.Id > $1.Id }
            success?(ChallengeModel(models: sortModels, total: total_record, code: code, usedCodeNumber: usedCodeNumber, totalCodeNumber: totalCodeNumber))
        }, failure: failure)
    }
    
    static func loadNetworkSponsorData(success:(([ReferralNetworkModel]) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        let handleNetworkSponsorData: (Any) -> Void = { data in
            
            guard let result = data as? [String: Any],
                  let isSuccess = result["success"] as? Bool,
                  isSuccess,
                  let tree = result["tree"] as? [[String: Any]] else {
                failure?(SCAError.dataException)
                return
            }
            
            var models: [ReferralNetworkModel] = []
            for item in tree {
                for (key, value) in item {
                    guard let dict = value as? [String: Any] else { continue }
                    
                    let account = dict.stringValue("username")
                    let title = dict.stringValue("power_active_disp")
                    models.append(ReferralNetworkModel(Id: key, title: title, account: account))
                }
            }
            
            let sortModels = models.sorted { $0.Id < $1.Id }
            
            success?(sortModels)
            
            if let jsonString = result.toJSONString() {
                let mineModuleModel = MineModuleModel.current
                mineModuleModel.referralNetworkData = jsonString
                mineModuleModel.asyncInsertOrReplace()
            }
        }
        
        let mineModuleModel = MineModuleModel.current
        if let dict = mineModuleModel.referralNetworkData.toObject() as? [String: Any] {
            handleNetworkSponsorData(dict)
        }
        
        NetworkManager.shared.post(url: APIEndpoint.networkSponsor, parameters: [
            "type": "h"
        ], success: { data in
            handleNetworkSponsorData(data)
        }, failure: failure)
        
    }
    
    static func loadMatrixData(success:(([MatrixNetworkModel]) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        let handleMatrixData: (Any) -> Void = { data in
            
            guard let result = data as? [String: Any],
                  let isSuccess = result["success"] as? Bool,
                  isSuccess,
                  let tree = result["net"] as? [String: Any] else {
                failure?(SCAError.dataException)
                return
            }
            
            var models: [MatrixNetworkModel] = []
            for (_, netValue) in tree {
                guard let netDict = netValue as? [String: Any] else { continue }
                
                for (key, value) in netDict {
                    guard let dict = value as? [String: Any] else { continue }
                    models.append(MatrixNetworkModel(Id: key, dict: dict))
                }
            }
            let sortModels = models.sorted { $0.Id > $1.Id }
            success?(sortModels)
            
            if let jsonString = result.toJSONString() {
                let mineModuleModel = MineModuleModel.current
                mineModuleModel.matrixData = jsonString
                mineModuleModel.asyncInsertOrReplace()
            }
        }
        
        let mineModuleModel = MineModuleModel.current
        if let dict = mineModuleModel.matrixData.toObject() as? [String: Any] {
            handleMatrixData(dict)
        }
        
        NetworkManager.shared.post(url: APIEndpoint.matrix, success: { data in
            handleMatrixData(data)
        }, failure: failure)
        
    }
    
    static func redeemPrize(code: String, success:(() -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        NetworkManager.shared.post(url: APIEndpoint.redeemPrize, parameters: [
            "code": code
        ], success: { data in
            guard let result = data as? [String: Any],
                  let isSuccess = result["success"] as? Bool,
                  isSuccess else {
                failure?(SCAError.dataException)
                return
            }
            success?()
        }, failure: failure)
        
    }
    
    static func loadMineBenefitsData(success:((MineBenefitsInfo) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["page"] = "1"
        
        NetworkManager.shared.post(url: APIEndpoint.benefitsList, parameters: parameters, success: { data in
            guard let result = data as? [String: Any],
                  let datalist = result["datalist"] as? [String: Any],
                  let data = datalist["data"] as? [String: Any],
                  let eventInfo = datalist["event"] as? [String: Any],
                  let refInfo = eventInfo["ref"] as? [String: Any],
                  let selfInfo = eventInfo["self"] as? [String: Any],
                  let totalPage = datalist["total_page"] as? Int else {
                failure?(SCAError.dataException)
                return
            }
            
            var models: [MineBenefitsModel] = []
            
            for (_ , dataValue) in data {
                guard let dict = dataValue as? [String: Any] else {
                    continue
                }
                
                models.append(MineBenefitsModel(dict: dict))
            }
            
            let ref = refInfo.intValue("count")
            let mySelf = selfInfo.intValue("count")
            
            let sortModels = models.sorted { $0.Id > $1.Id }
            
            success?(MineBenefitsInfo(models: sortModels, totalPage: totalPage, ref: ref, mySelf: mySelf))
        }, failure: failure)
    }

    static func loadConversionData(Id: Int, success:((ConversionInfo) -> Void)? = nil, failure:((_ error: Error) -> Void)? = nil) {
        
        var parameters: [String: Any] = [:]
        parameters["step"] = "ini"
        
        NetworkManager.shared.post(url: String(format: APIEndpoint.conversionRing, String(Id)), parameters: parameters, success: { data in
            
            guard let result = data as? [String: Any],
                  let ringColor = result["ring_color"] as? [String: Any],
                  let input = result["input"] as? [String: Any],
                  
                    let ringSize = input["ring_size"] as? [String: Any],
                  let ringSizeOptionValidate = ringSize["option_validate"] as? [Int],
                  let ringSizeOption = ringSize["option"] as? [String: Any],
                  
                    let ringType = input["ring_type"] as? [String: Any],
                  let ringTypeOption = ringType["option"] as? [String: Any],
                  
                  let countryCode = input["country_code"] as? [String: Any],
                  let countryCodeOption = countryCode["option"] as? [String: Any],
                  let countryCodeOptionValidate = countryCode["option_validate"] as? [String],

                  let mobileCountryCode = input["mobile_country_code"] as? [String: Any],
                  let mobileCountryCodeOption = mobileCountryCode["option"] as? [String: Any],
                  let mobileCountryCodeOptionValidate = mobileCountryCode["option_validate"] as? [String] else {
                
                failure?(SCAError.dataException)
                return
            }
            
            var sizeModels: [RingSizeModel] = []
            
            for sizeKey in ringSizeOptionValidate {
                
                let sizeValue = ringSizeOption.stringValue(String(sizeKey))
                guard let sizeDict = ringColor[String(sizeKey)] as? [String: Any] else {
                    continue
                }
                
                var typeModels: [RingTypeModel] = []
                
                for (type, type_Dict) in sizeDict {
                    
                    var colorModels: [RingColorModel] = []
                    
                    
                    guard let typeDict = type_Dict as? [String: String] else {
                        continue
                    }
                    
                    
                    for (colorKey, colorValue) in typeDict {
                        colorModels.append(RingColorModel(key: colorKey, value: colorValue))
                    }
                    
                    let sortColorModels = colorModels.sorted { $0.key > $1.key }
                    
                    let typeModel = RingTypeModel(key: type, value: ringTypeOption.stringValue(type), colorModels: sortColorModels)
                    typeModels.append(typeModel)
                }

                sizeModels.append(RingSizeModel(key: String(sizeKey), value: sizeValue, typeModels: typeModels.sorted { $0.key > $1.key }))
                
            }
            
            printf("sizeModels=\(sizeModels)")
            
            var countryCodeModels: [CountryModel] = []

            for countryCodeKey in countryCodeOptionValidate {
                let countryCodeValue = countryCodeOption.stringValue(countryCodeKey)
                countryCodeModels.append(CountryModel(code: countryCodeKey, value: countryCodeValue))
            }
            
            var mobileCountryCodeModels: [MobileCountryCodeModel] = []
            for mobileCountryCodeKey in mobileCountryCodeOptionValidate {
                let mobileCountryCodeValue = mobileCountryCodeOption.stringValue(mobileCountryCodeKey)
                mobileCountryCodeModels.append(MobileCountryCodeModel(code: mobileCountryCodeKey, value: mobileCountryCodeValue))
            }
            
           let info = ConversionInfo(sizeModels: sizeModels, countryCodeModels: countryCodeModels, mobileCountryCodeModels: mobileCountryCodeModels)
        
           success?(info)
        }, failure: failure)
    }
    
    
}
